package com.vf.admin.fiwork.util;

import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
 * 时间工具类
 *
 * @author anxiang.li
 * @create 2018-04-02-19:56
 */
public class DateUtils extends org.apache.commons.lang.time.DateUtils {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final ZoneId zoneId = ZoneId.systemDefault();

    /**
     * 获取在某天的基础上增加或减少N天
     *
     * @param date 某天
     *             加上或减少的天数，正数为加，负数为减。
     * @return
     */
    public static Date getDateAfterDays(Date date, int days) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_YEAR, days);
        return c.getTime();
    }

    /**
     *
     * @param days 天数
     * @return
     */
    public static Long getMinutesByDays(int days) {
        return Long.valueOf(days * 24 * 60);
    }

    /**
     * 获取时间所在周的最第一天和最后一天
     * @param  date 时间，如果没有则获取当前时间
     * @return Map<String,String> （firstDay,lastDay）
     */
    public static Map<String,String> getWeekFirstLastDay(String date){
        Map<String,String> week = new HashMap<>();
        LocalDate nowTime = null;
        if(StringUtils.isEmpty(date)){
            nowTime = LocalDate.now();
        }else{
            nowTime = LocalDate.parse(date);
        }
        //当前周的第一天
        TemporalAdjuster FIRST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
        week.put("firstDay",nowTime.with(FIRST_OF_WEEK)+" 00:00:00");
        //当前周的最后一天
        TemporalAdjuster LAST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
        week.put("lastDay",nowTime.with(LAST_OF_WEEK)+" 23:59:59");
        return week;
    }

    /**
     * 获取当前时间的所属星期的，第一天日期，最后一天日期
     * @return Map<String,Integer>
     */
    public static Map<String,Integer> getWeekFirstDayLastDay(String date){
        Map<String,Integer> day = new HashMap<>();
        Map<String,String> week = getWeekFirstLastDay(date);
        String firstDay = week.get("firstDay");
        int startDay = Integer.parseInt(firstDay.split(" ")[0].split("-")[2]);
        String lastDay = week.get("lastDay");
        int endDay = Integer.parseInt(lastDay.split(" ")[0].split("-")[2]);
        day.put("startDay",startDay);
        day.put("endDay",endDay);
        return day;
    }

    /**
     * 获得本周的每一天
     * @return
     */
    public static List<Date> getWeekEveryDay() {
        LocalDate nowTime = LocalDate.now();
        Calendar calendar = Calendar.getInstance();

        //周的第一天
        TemporalAdjuster FIRST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
        String firstDay = nowTime.with(FIRST_OF_WEEK).toString();

        //周的最后一天
        TemporalAdjuster LAST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
        String lastDay = nowTime.with(LAST_OF_WEEK).toString();

        List<Date> dateList = getDayList(parseDate(firstDay,"yyyy-MM-dd"),parseDate(lastDay,"yyyy-MM-dd"));

        return dateList;
    }

    /**
     * 获取当前时间所在月的最第一天和最后一天
     * @return Map<String,String> （firstDay,lastDay）
     */
    public static Map<String,String> getMonthFirstLastData(String date){
        Map<String,String> month = new HashMap<>();
        LocalDate localDate = null;
        if(StringUtils.isEmpty(date)){
            localDate = LocalDate.now();
        }else{
            localDate = LocalDate.parse(date);
        }
        LocalDate firstDay = localDate.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDay = localDate.with(TemporalAdjusters.lastDayOfMonth());
        month.put("firstDay",firstDay.toString()+" 00:00:00");
        month.put("lastDay",lastDay.toString()+" 23:59:59");
        return month;
    }

    /**
     * 获取月的第一天日期，最后一天的日期
     * @param date
     * @return Map<String,Integer>
     */
    public static Map<String,Integer> getMonthFirstDayLastDay(String date){
        Map<String,String> month = getMonthFirstLastData(date);
        Map<String,Integer> day = new HashMap<>();
        String firstDay = month.get("firstDay");
        int startDay = Integer.parseInt(firstDay.split(" ")[0].split("-")[2]);
        String lastDay = month.get("lastDay");
        int endDay = Integer.parseInt(lastDay.split(" ")[0].split("-")[2]);
        day.put("startDay",startDay);
        day.put("endDay",endDay);
        return day;
    }

    /**
     * 获取某一个时间的前几周或后几周的时间列表
     * @param weekNum 获取周量
     * @param date 时间，不传则获取当前时间
     * @param isSub true向前获，false向后获取
     * @return List<List<Date>>
     */
    public static List<List<Date>> getDateALLWeek(int weekNum,String date,boolean isSub){
        List<List<Date>> lists = new ArrayList<>(weekNum);
        LocalDate nowTime;
        if(StringUtils.isNotEmpty(date)){
            nowTime = LocalDate.parse(date);
        }else{
            nowTime = LocalDate.now();
        }
        Calendar calendar = Calendar.getInstance();
        for(int i=0; i<weekNum ;i++){
            //周的第一天
            TemporalAdjuster FIRST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
            String firstDay = nowTime.with(FIRST_OF_WEEK).toString();

            //周的最后一天
            TemporalAdjuster LAST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
            String lastDay = nowTime.with(LAST_OF_WEEK).toString();

            //获取周所包含的日期列表
            List<Date> dateList = getDayList(parseDate(firstDay,"yyyy-MM-dd"),parseDate(lastDay,"yyyy-MM-dd"));
            lists.add(dateList);

            if(isSub){//减去一天
                Date newDate = parseDate(firstDay.toString(),"yyyy-MM-dd");
                calendar.setTime(newDate);
                calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1);
            }else{//加一天
                Date newDate = parseDate(lastDay.toString(),"yyyy-MM-dd");
                calendar.setTime(newDate);
                calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 1);
            }
            //重新得到时间
            nowTime = LocalDate.parse(format(calendar.getTime(),"yyyy-MM-dd"));
        }
        if(isSub){
            List<List<Date>> _lists = new ArrayList<>();
            int size = lists.size();
            IntStream.range(1,lists.size()+1).forEach(index->{
                List<Date> _l = lists.get(size-index);
                _lists.add(_l);
            });
            return _lists;
        }
        return lists;
    }

    /**
     * 获取某一个时间向前遍移N个月，或向后遍移N个月
     * @param monthNum 获取月量
     * @param date 时间，不传则获取当前时间
     * @param isSub true向前获，false向后获取
     * @return Map<String,Date>
     */
    public static Map<String,Date> getDateStartAndEndMonth(int monthNum,String date,boolean isSub){
        LocalDate localDate;
        if(StringUtils.isNotEmpty(date)){
            localDate = LocalDate.parse(date);
        }else{
            localDate = LocalDate.now();
        }
        Map<String,String> dataMap = getMonthFirstLastData(localDate.toString());
        String firstDay  = dataMap.get("firstDay");
        String lastDay  = dataMap.get("lastDay");
        Date _firstDay = parseDate(firstDay,"yyyy-MM-dd HH:mm:ss");
        Date _lastDay = parseDate(lastDay,"yyyy-MM-dd HH:mm:ss");
        Date startTime = null;
        Date endTime = null;
        if(isSub){
            startTime = addMonths(_firstDay,((monthNum-1) * -1));
            dataMap = getMonthFirstLastData(format(startTime,"yyyy-MM-dd"));
            startTime = parseDate(dataMap.get("firstDay"),"yyyy-MM-dd HH:mm:ss");
            endTime = _lastDay;
        }else{
            startTime = _firstDay;
            endTime = addMonths(_firstDay,(monthNum-1));
            dataMap = getMonthFirstLastData(format(endTime,"yyyy-MM-dd"));
            endTime = parseDate(dataMap.get("lastDay"),"yyyy-MM-dd HH:mm:ss");
        }
        Map<String,Date> dateMap = new HashMap<>();
        dateMap.put("startTime",startTime);
        dateMap.put("endTime",endTime);
        return dateMap;
    }

    /**
     * 获取指定时间的24小时列表
     * @param date
     * @return List<Date>
     */
    public static List<Date> getDay24HourList(Date date){
        List<Date> dateList = new ArrayList<>(24);
        String strTime = format(date,"yyyy-MM-dd");
        IntStream.range(0,24).forEach(index->{
            String time;
            if(index <= 9){
                time = strTime + " 0"+index;
            }else{
                time = strTime +" "+ index;
            }
            dateList.add(parseDate(time,"yyyy-MM-dd HH"));
        });
        return dateList;
    }

    /**
     * {@link Date} to {@link LocalDateTime}
     *
     * @param date 日期时间
     * @return 日期时间
     */
    public static LocalDateTime convertDateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), zoneId);
    }

    /**
     * {@link Date} to {@link LocalDate}
     *
     * @param date 日期时间
     * @return 日期时间
     */
    public static LocalDate convertDateToLocalDate(Date date) {
        return convertDateToLocalDateTime(date).toLocalDate();
    }

    /**
     * 年份的范围
     *
     * @return 年份范围
     */
    public static List<Integer> getYearRange() {
        return getYearRange(2016);
    }

    /**
     * 年份的范围
     *
     * @param startInclusive 起止年份
     * @return 年份范围
     */
    public static List<Integer> getYearRange(int startInclusive) {
        return getYearRange(startInclusive, LocalDate.now().getYear() + 2);
    }

    /**
     * 年份的范围
     *
     * @param startInclusive 起止年份
     * @return 年份范围
     */
    public static List<Integer> getYearRange(int startInclusive, int endInclusive) {
        return IntStream.rangeClosed(startInclusive, endInclusive)
                .boxed()
                .collect(Collectors.toList());
    }

    public static String format(Date time) {
        return simpleDateFormat.format(time);
    }

    public static String format(Date time, String pattern) {
        simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(time);
    }

    /**
     * 参数时间与现在相差的天数
     *
     * @param source
     * @return
     */
    public static int daysBeforeNow(Date source) {
        if (source == null) {
            return 0;
        } else {
            Calendar now = Calendar.getInstance();
            Calendar old = Calendar.getInstance();
            old.setTime(source);
            old.set(11, 0);
            old.set(12, 0);
            old.set(13, 0);
            now.set(11, 0);
            now.set(12, 0);
            now.set(13, 0);
            long l = old.getTimeInMillis() - now.getTimeInMillis();
            return BigDecimal.valueOf(l).divide(BigDecimal.valueOf(86400000L), RoundingMode.HALF_UP).intValue();
        }
    }


    public static Date addByDate(Date date, int type, int value) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        switch (type) {
            case 5:
                now.set(5, now.get(5) + value);
                break;
            case 11:
                now.set(11, now.get(11) + value);
                break;
            case 12:
                now.set(12, now.get(12) + value);
        }

        return now.getTime();
    }

    public static Date parseDate(String str,String patterns){
        try {
            return parseDate(str,new String[]{patterns});
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取两个时间段内的所有的日期列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 时间列表
     */
    public static List<Date> getDayList(Date startTime,Date endTime){
        List<Date> dateList = new ArrayList<>();
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(startTime);
        while(startTime.getTime() <= endTime.getTime()){
            dateList.add(tempStart.getTime());
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
            startTime = tempStart.getTime();
        }
        return dateList;
    }

    /**
     * 获取两个时间段内的所有周的第一天
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 时间列表
     */
    public static List<Date> getWeekList(Date startTime,Date endTime){
        List<Date> dateList = new ArrayList<>();
        return dateList;
    }

    /**
     * 获取两个时间段内的所有的月的时间列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    public static List<Date> getMonthsList(Date startTime, Date endTime){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Period period = Period.between(LocalDate.parse(simpleDateFormat.format(startTime)),LocalDate.parse(simpleDateFormat.format(endTime)));
        int months = period.getMonths();
        months =months + period.getYears() * 12;
        List<Date> dateList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);
        dateList.add(calendar.getTime());
        for (int i = 0; i < months; i++) {
            calendar.add(Calendar.MONTH,1);
            Date data = calendar.getTime();
            dateList.add(data);
        }
        return dateList;
    }

    /**
     * 获取当前时间的前几天
     * @param day
     * @return
     */
    public  static Date getPastDate(int day){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.DATE, - day);
        return  c.getTime();
    }


    /**
     * 当前时间到午夜24点
     * 返回，秒
     */
    public static Long currentToTwentyFour() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH)+2);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        return (cal.getTimeInMillis() - System.currentTimeMillis())/1000;
    }


    /**
     * 两个时间相差的分钟数与现在相差的分钟数
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    public static int getMinByDiff(Date startTime, Date endTime) {

        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        start.setTime(startTime);
        end.setTime(endTime);
        long duration = end.getTimeInMillis() - start.getTimeInMillis();
        if (duration < 0) {
            return 0;
        }
        return BigDecimal.valueOf(duration).divide(BigDecimal.valueOf(60000L), RoundingMode.HALF_UP).intValue();
    }

    /**
     * 判断两个日期是否是同一天
     * @param d1
     * @param d2
     * @return
     */
    public static boolean isSameDate(Date d1 ,Date d2){
        if (null == d1 || null == d2)
            return false;

        if(Math.abs(d1.getTime() - d2.getTime()) > 3600000*24)
            return false;

        Calendar c1 = Calendar.getInstance();
        c1.setTime(d1);
        Calendar c2 = Calendar.getInstance();
        c1.setTime(d2);
        if(c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH))
            return false;

        return true;
    }


    /**
     * 获取未来几天的日期
     */
    public static List<String> getFutureDate(int past) {
        List<String> futureDate = new ArrayList<>();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");


        LocalDate now = LocalDate.now();
        LocalDate localDate = null;

        for(int i = 0; i <= past; i++) {
            if(i == 0) {
                futureDate.add(dateTimeFormatter.format(now));
            } else {
                localDate = now.plusDays(i);
                futureDate.add(dateTimeFormatter.format(localDate));
            }
        }
        return futureDate;
    }

    /**
     * 获取当前时间到凌晨0点多少秒
     *
     * @return
     */
    public static Integer calculateCurrentTime2SecondDaySec() {
        Long currentTime = System.currentTimeMillis();
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(currentTime);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DATE, 1);
        Long endTime = calendar.getTimeInMillis();
        return (int) (endTime - currentTime) / 1000;
    }

    public static String subYear(Date date, Integer num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, - num);
        Date nextDay = calendar.getTime();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(nextDay);
    }

    public static long hourToSeconds(Integer hour) {
        return hour * 60 * 60;
    }
}
